package com.xyz.wll.es.manager.ui.model;



import com.xyz.wll.es.util.EsUtil;
import com.xyz.wll.es.util.model.DocRecord;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class MyTableModel extends AbstractTableModel {
    private EsUtil esUtil;
    private String index;
    private List<DocRecord> docRecords;
    private Map<String,String> fieldMappings;
    private String[] columns;
    private JTextArea statusInfo;

    public MyTableModel(EsUtil esUtil, String indexName, List<DocRecord> docRecords) throws IOException {
        this.esUtil = esUtil;
        index = indexName;
        if(docRecords == null) {
            this.docRecords = new ArrayList<>();
        } else {
            this.docRecords = docRecords;
        }
        fieldMappings = esUtil.getMappings(indexName);
        if(fieldMappings != null) {
            columns = new String[fieldMappings.size()];
            fieldMappings.keySet().toArray(columns);
        } else {
            columns = new String[0];
        }
    }

    public List<DocRecord> getDocRecords() {
        return this.docRecords;
    }

    public String[] getColumns() {
        String[] result = new String[columns.length+1];
        result[0] = "_id";
        for(int i=0; i<columns.length; i++) {
            result[i+1] = columns[i];
        }
        return result;
    }

    public void setStatusInfo(JTextArea statusInfo) {
        this.statusInfo = statusInfo;
    }

    @Override
    public int getRowCount() {
        if(docRecords != null) {
            return docRecords.size();
        }
        return 0;
    }

    @Override
    public int getColumnCount() {
        return columns.length+1;
    }

    @Override
    public String getColumnName(int columnIndex) {
        if(columns != null) {
            if(columnIndex == 0) {
                return "_id";
            } else {
                return columns[columnIndex-1];
            }
        }
        return null;
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return String.class;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return true;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        if(docRecords.size() > 0) {
            if(columnIndex == 0) {
                return docRecords.get(rowIndex).getId();
            } else {
                return docRecords.get(rowIndex).getSource().get(columns[columnIndex-1]);
            }
        }
        return null;
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        if(docRecords.size() > 0) {
            try {
                Object oldValue = getValueAt(rowIndex, columnIndex);
                if(!(oldValue != null && aValue != null && aValue.equals(oldValue.toString()) || oldValue == null && aValue == null)) {
                    if (columnIndex == 0) {
                        if(esUtil.getDocument(index, aValue.toString()) == null) {
                            esUtil.deleteDocument(docRecords.get(rowIndex).getIndex(), docRecords.get(rowIndex).getType(), docRecords.get(rowIndex).getId());
                            setValue(aValue, rowIndex, columnIndex);
                            esUtil.insertDocument(docRecords.get(rowIndex));
                            fireTableCellUpdated(rowIndex, columnIndex);
                        } else {
                            statusInfo.setText(String.format("文档_id=%s已经存在", aValue.toString()));
                        }
                    } else {
                        setValue(aValue, rowIndex, columnIndex);
                        esUtil.updateDocument(docRecords.get(rowIndex));
                        fireTableCellUpdated(rowIndex, columnIndex);
                    }
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
                System.out.println(String.format("%d-%d %s", rowIndex, columnIndex, e.getMessage()));
                if(statusInfo != null) {
                    String columnName = getColumnName(columnIndex);
                    String columnType = fieldMappings.get(columnName);
                    statusInfo.setText(String.format("第%d行,第%d列,列名%s,类型%s 数值格式错误:%s", rowIndex, columnIndex, columnName, columnType, aValue));
                }
            }
        }
    }

    public void setValue(Object aValue, int rowIndex, int columnIndex) {
        if(docRecords.size() > 0) {
            if(columnIndex == 0) {
                docRecords.get(rowIndex).setId(aValue.toString());
            } else {
                String columnName = getColumnName(columnIndex);
                String columnType = fieldMappings.get(columnName);
                Object value = null;

                if(aValue != null && !aValue.toString().isEmpty()) {
                    switch (columnType) {
                        case "integer": {
                            value = Integer.parseInt(aValue.toString());
                            break;
                        }
                        case "long": {
                            value = Long.parseLong(aValue.toString());
                            break;
                        }
                        case "float": {
                            value = Float.parseFloat(aValue.toString());
                            break;
                        }
                        case "double": {
                            value = Double.parseDouble(aValue.toString());
                            break;
                        }
                        case "boolean": {
                            value = Boolean.parseBoolean(aValue.toString());
                            break;
                        }
                        case "keyword":
                        case "string": {
                            value = aValue.toString();
                            break;
                        }
                        default:
                            value = aValue.toString();
                            break;
                    }
                } else if(aValue != null && aValue.toString().isEmpty() && columnType.equals("string")) {
                    value = "";
                }
                docRecords.get(rowIndex).getSource().put(columns[columnIndex-1], value);
            }
        }
    }

    public void addRow(int rowIndex) {
        DocRecord docRecord = new DocRecord();
        if(docRecords.size() > 0) {
            DocRecord firstRecord = docRecords.get(0);
            docRecord.setIndex(firstRecord.getIndex());
            docRecord.setType(firstRecord.getType());
        } else {
            docRecord.setIndex(index);
            docRecord.setType("_doc");
        }
        //docRecord.setId(Integer.toString(rowIndex));

        TreeMap<String, Object> map = new TreeMap<>();
        for(String column : columns) {
            map.put(column, null);
        }
        docRecord.setSource(map);
        if(esUtil.upsertDocument(docRecord)) {
            if (rowIndex < 0 || rowIndex > docRecords.size()) {
                docRecords.add(docRecord);
                fireTableRowsInserted(docRecords.size() - 1, docRecords.size() - 1);
            } else {
                docRecords.add(rowIndex, docRecord);
                fireTableRowsInserted(rowIndex, rowIndex);
            }
        } else {
            statusInfo.setText(String.format("插入记录%s失败!!!,请检查文档id是否已经存在", docRecord.toString()));
        }
    }

    public void removeRows(int firstRow, int lastRow) {
        if(firstRow < 0 || lastRow >= docRecords.size()) {
            System.out.println(String.format("参数错误: firstRow={},lastRow={}", firstRow, lastRow));
            return;
        }

        for(int i = lastRow; i >= firstRow; i--) {
            DocRecord docRecord = docRecords.remove(i);
            esUtil.deleteDocument(docRecord.getIndex(), docRecord.getType(), docRecord.getId());
        }
        fireTableRowsDeleted(firstRow, lastRow);
    }

    public void updateRow(int row, String[] fields) {
        if(row < 0 || row >= docRecords.size()) {
            System.out.println(String.format("row越界, row=%d, max_row_size=%d",row, docRecords.size()));
            return;
        }
        if(fields.length != getColumnCount()) {
            System.out.println(String.format("fields.length[%d] != columns.length[%d]", fields.length, getColumnCount()));
            return;
        }

        boolean errorOccur = false;
        for (int j = 0; j < getColumnCount() && j < fields.length; j++) {
            try {
                if(j==0) {
                    setValueAt(fields[j], row, j);
                } else {
                    setValue(fields[j], row, j);
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
                System.out.println(String.format("%d-%d %s", row, j, e.getMessage()));
                errorOccur = true;
            }
        }

        if(!errorOccur) {
            esUtil.updateDocument(docRecords.get(row));
            fireTableRowsUpdated(row, row);
        }
    }

    public void addRows(List<DocRecord> rows) {
        int startRow = docRecords.size();
        int rowCount = rows.size();
        for(DocRecord row : rows) {
            row.setIndex(index);
            docRecords.add(row);
            esUtil.upsertDocument(row);
        }
        fireTableRowsUpdated(startRow,startRow+rowCount);
    }
}
